#include <sys/socket.h>
#include <netinet/in.h> //IPPROTO_TCP
#include <unistd.h>
// #include <sys/types.h>
// #include <errno.h>

#include "./Acceptor.h"
#include "../utility/Logger.h"
#include "../net/InetAddress.h"

static int CreateNonblockingSockFd()
{
    int sockFd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);
    if (sockFd < 0)
    {
        LOG_FATAL("%s:%s:%d listen socket create err:%d\n", __FILE__, __FUNCTION__, __LINE__, errno);
    }
    return sockFd;
}

Acceptor::Acceptor(EventLoop *loop, const InetAddress &listenAddr, bool reusePort)
    : loop_(loop),
      acceptSocket_(CreateNonblockingSockFd()),
      acceptChannel_(this->loop_, this->acceptSocket_.getFd()),
      isListen_(false)
{
    this->acceptSocket_.setReuseAddr(true);
    // TODO: 使用reusePort而不是默认值
    this->acceptSocket_.setReusePort(true);

    this->acceptSocket_.bindAddr(listenAddr);

    // TcpServer::start() -> Acceptor::listen() 有新用户连接执行回调
    // 回调：accept => connfd => 打包成Channel => 唤醒subloop
    this->acceptChannel_.setReadCallback(std::bind(&Acceptor::handleRead, this));
}

// 新连接回调1
void Acceptor::handleRead()
{
    InetAddress peerAddr{};
    int connFd = this->acceptSocket_.accept(&peerAddr);
    if (connFd >= 0)
    {
        // 新连接回调2TcpServer::newConnection()
        // connfd => 打包成Channel => 唤醒subloop
        if (this->newConnCallback_)
        {
            this->newConnCallback_(connFd, peerAddr);
        }
        else
        {
            ::close(connFd);
        }
    }
    else
    {
        // TODO: connFd创建失败更细致处理：调整数量；部署集群等
        LOG_ERROR("%s:%s:%d accept err:%d\n", __FILE__, __FUNCTION__, __LINE__, errno);
        if (errno == EMFILE)
        {
            LOG_ERROR("%s:%s:%d sockfd reached limit\n", __FILE__, __FUNCTION__, __LINE__);
        }
    }
}

Acceptor::~Acceptor()
{
    this->acceptChannel_.disableAllEvent();
    this->acceptChannel_.removeChannel();
}

void Acceptor::setNewConnCallback(const NewConnCallback &cb)
{
    this->newConnCallback_ = cb;
}

bool Acceptor::getIsListen() const
{
    return this->isListen_;
}

void Acceptor::listen()
{
    this->isListen_ = true;

    this->acceptSocket_.listen();           // listen
    this->acceptChannel_.enableReadEvent(); // 注册到Poller上监听
}